package com.intretech.tj.global.parent;

import io.smallrye.mutiny.Multi;
import io.vertx.mutiny.core.Vertx;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;

/**
 * 触发器父类<br/>
 * 子类应该在注释中说明触发器key<br/>
 * 与触发函数接收什么类型的函数
 *
 * @param <T> 用以传达到触发的函数
 */
@Slf4j
public class TriggerParent<T> {
    public static final String ALL = "all";

    class Trigger {
        /**
         * 触发器标识
         */
        String title;
        /**
         * 触发函数
         */
        Consumer<T> consumer;

        public Trigger(String title, Consumer<T> consumer) {
            this.title = title;
            this.consumer = consumer;
        }
    }

    /**
     * 触发器存储池<br/>
     * key:根据实际情况判断<br/>
     * value:被触发的函数
     */
    private final Map<String, List<Trigger>> triggerMap = new ConcurrentHashMap<>();

    public void trigger(String key, T object) {
        if (triggerMap.containsKey(key))
            Multi.createFrom().items(triggerMap.get(key).stream())
                    .onItem().transform(trigger -> Vertx.currentContext().executeBlocking(() -> {
                        trigger.consumer.accept(object);
                        return object;
                    })).subscribe().with(objectUni -> objectUni.subscribe().with(trigger -> log.info("触发器::写入" + object)));
    }

    /**
     * 写入触发器
     *
     * @param key     任意关键字
     * @param title   触发器标识
     * @param trigger 触发函数
     */
    public void setTrigger(String key, String title, Consumer<T> trigger) {
        if (triggerMap.containsKey(key)) {
            if (!Objects.isNull(triggerMap.get(key)))
                triggerMap.get(key).add(new Trigger(title, trigger));
        } else triggerMap.put(key, new CopyOnWriteArrayList<>(List.of(new Trigger(title, trigger))));
    }

    /**
     * 删除触发器
     *
     * @param key   写入时的关键字
     * @param title 触发器标识
     */
    public void removeTrigger(String key, String title) {
        if (triggerMap.containsKey(key)) {
            triggerMap.get(key).removeIf(trigger -> trigger.title.equals(title));
        }
    }

}
